package my.projects.jandan.test;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.GzipDecompressingEntity;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;

/**
 * @see 
 *      ==============================================================================================
 *      =======
 * @see 在开发HTTPS应用时，时常会遇到两种情况
 * @see 1、要么测试服务器没有有效的SSL证书,客户端连接时就会抛异常
 * @see javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
 * @see 2、要么测试服务器有SSL证书,但可能由于各种不知名的原因,它还是会抛一个堆烂码七糟的异常
 * @see 
 *      ==============================================================================================
 *      =======
 * @see 由于我们这里使用的是HttpComponents-Client-4.1.2创建的连接，所以，我们就要告诉它使用一个不同的TrustManager
 * @see TrustManager是一个用于检查给定的证书是否有效的类
 * @see SSL使用的模式是X.509....对于该模式,Java有一个特定的TrustManager,称为X509TrustManager
 * @see 所以我们自己创建一个X509TrustManager实例
 * @see 而在X509TrustManager实例中，若证书无效，那么TrustManager在它的checkXXX()方法中将抛出CertificateException
 * @see 既然我们要接受所有的证书,那么X509TrustManager里面的方法体中不抛出异常就行了
 * @see 然后创建一个SSLContext并使用X509TrustManager实例来初始化之
 * @see 接着通过SSLContext创建SSLSocketFactory，最后将SSLSocketFactory注册给HttpClient就可以了
 * @see 
 *      ==============================================================================================
 *      =======
 * @create Jul 30, 2012 1:11:52 PM
 * @author 玄玉(http://blog.csdn/net/jadyer)
 */
public class HttpClientUtils2 {
//    private static final String LOGIN_URL = "https://72.52.124.215/logging.php?action=login";

    public static void main(String[] args) throws Exception {
        // Map<String, String> params = new HashMap<String, String>();
        // params.put("TransName", "IQSR");
        // params.put("Plain",
        // "transId=IQSR~|~originalorderId=2012~|~originalTransAmt= ~|~merURL= ");
        // params.put("Signature",
        // "9b759887e6ca9d4c24509d22ee4d22494d0dd2dfbdbeaab3545c1acee62eec7");
        // sendSSLPostRequest("https://www.cebbank.com/per/QueryMerchantEpay.do", params);

//         sendSSLPostRequest("https://72.52.124.215/", null);
         sendSSLPostRequest("https://72.52.124.215/forumdisplay.php?fid=37", null);
    }

    /**
     * 向HTTPS地址发送POST请求
     * 
     * @param reqURL 请求地址
     * @param params 请求参数
     * @return 响应内容
     */
    @SuppressWarnings("finally")
    public static String sendSSLPostRequest(String reqURL, Map<String, String> params) {
        long responseLength = 0; // 响应长度
        String responseContent = null; // 响应内容
        HttpClient httpClient = new DefaultHttpClient(); // 创建默认的httpClient实例
        httpClient.getParams()
                .setParameter(CoreProtocolPNames.USER_AGENT,
                        "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)")
                .setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, "GBK");

        X509TrustManager xtm = new X509TrustManager() { // 创建TrustManager
                    public void checkClientTrusted(java.security.cert.X509Certificate[] arg0,
                            String arg1) throws CertificateException {}

                    public void checkServerTrusted(java.security.cert.X509Certificate[] arg0,
                            String arg1) throws CertificateException {}

                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }
                };

        // 这个好像是HOST验证
        X509HostnameVerifier hostnameVerifier = new X509HostnameVerifier() {
            public boolean verify(String arg0, javax.net.ssl.SSLSession arg1) {
                return true;
            }

            public void verify(String arg0, javax.net.ssl.SSLSocket arg1) throws IOException {}

            public void verify(String arg0, String[] arg1, String[] arg2) throws SSLException {}

            public void verify(String arg0, X509Certificate arg1) throws SSLException {}
        };
        try {
            // TLS1.0与SSL3.0基本上没有太大的差别，可粗略理解为TLS是SSL的继承者，但它们使用的是相同的SSLContext
            SSLContext ctx = SSLContext.getInstance("TLS");

            // 使用TrustManager来初始化该上下文，TrustManager只是被SSL的Socket所使用
            ctx.init(null, new TrustManager[] {xtm}, null);

            // 创建SSLSocketFactory
            SSLSocketFactory socketFactory = new SSLSocketFactory(ctx);

            // 去除host验证
            socketFactory.setHostnameVerifier(hostnameVerifier);

            // 通过SchemeRegistry将SSLSocketFactory注册到我们的HttpClient上
            httpClient.getConnectionManager().getSchemeRegistry()
                    .register(new Scheme("https", 443, socketFactory));

            HttpPost httpPost = new HttpPost(reqURL); // 创建HttpPost
            httpPost.setHeader("Accept-Encoding", "gzip, deflate");

            // Cookie
            httpPost.setHeader(
                    "Cookie",
                    "cdb_cookietime=315360000;"
                            + "cdb_smile=1D1;"
                            + "cdb_sid=nRXSzm;"
                            + "cdb_auth=FJ4rRi5aiid%2BW7HLU4r47DpZUHe0pgLAq6XvwAzgw0k0TvWZn1yFq0famjX7HaOXGimzRujNZWI;"
                            + "cdb_visitedfid=37");
            httpPost.setHeader("Referer", "https://72.52.124.215/index.php");
            httpPost.setHeader("Host", "72.52.124.215");
            httpPost.setHeader("Connection", "Keep-Alive");


            if (params != null) {
                List<NameValuePair> formParams = new ArrayList<NameValuePair>(); // 构建POST请求的表单参数
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    formParams.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                }
                httpPost.setEntity(new UrlEncodedFormEntity(formParams, "UTF-8"));
            }

            HttpResponse response = httpClient.execute(httpPost); // 执行POST请求
            HttpEntity entity = response.getEntity(); // 获取响应实体
            
            
            if (null != entity) {
                responseLength = entity.getContentLength();
                responseContent = EntityUtils.toString(new GzipDecompressingEntity(entity), "GBK");
                EntityUtils.consume(entity); // Consume response content
            }
            System.out.println("请求地址: " + httpPost.getURI());
            System.out.println("响应状态: " + response.getStatusLine());
            System.out.println("响应长度: " + responseLength);
            System.out.println("响应内容: " + responseContent);

            /*
             * FileWriter fw = null; File f = new File("D:\\电驴.html");
             * 
             * try { if(!f.exists()){ f.createNewFile(); } fw = new FileWriter(f); BufferedWriter
             * out = new BufferedWriter(fw); out.write(responseContent, 0,
             * responseContent.length()-1); out.close();
             * System.out.println("end====================="); } catch (IOException e) {
             * e.printStackTrace(); }
             */
            /*
             * FileOutputStream o = new FileOutputStream("D:\\电驴2.html");
             * o.write(responseContent.getBytes("GBK")); o.close();
             */

        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            httpClient.getConnectionManager().shutdown(); // 关闭连接,释放资源
            return responseContent;
        }
    }
}
